package com.xzzz.expand.gateway.application.config;

import com.xzzz.common.base.pojo.R;
import com.xzzz.common.base.pojo.RCode;
import com.xzzz.common.base.util.json.JsonUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.web.ErrorProperties;
import org.springframework.boot.autoconfigure.web.WebProperties;
import org.springframework.boot.autoconfigure.web.reactive.error.DefaultErrorWebExceptionHandler;
import org.springframework.boot.web.error.ErrorAttributeOptions;
import org.springframework.boot.web.reactive.error.ErrorAttributes;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpStatus;
import org.springframework.web.reactive.function.server.*;
import org.springframework.web.server.ResponseStatusException;

import java.util.Map;

/**
 * @author xzzz
 */
@Slf4j
public class WrapperExceptionHandler extends DefaultErrorWebExceptionHandler {

    public WrapperExceptionHandler(ErrorAttributes errorAttributes,
                                   WebProperties.Resources resources,
                                   ErrorProperties errorProperties,
                                   ApplicationContext applicationContext) {
        super(errorAttributes, resources, errorProperties, applicationContext);
    }

    /**
     * 处理异常, 并封装为 Map 返回, 默认返回500, 其他情况按响应码处理
     * @param request 请求
     * @param options 配置
     * @return 异常封装对象
     */
    @Override
    protected Map<String, Object> getErrorAttributes(ServerRequest request, ErrorAttributeOptions options) {
        RCode rCode = RCode.INTERNAL_SERVER_ERROR;
        Throwable throwable = super.getError(request);

        if (throwable instanceof ResponseStatusException){
            ResponseStatusException rse = (ResponseStatusException) throwable;
            if (rse.getStatus() == HttpStatus.NOT_FOUND){
                rCode = RCode.NOT_FOUND;
            } else if (rse.getStatus() == HttpStatus.SERVICE_UNAVAILABLE) {
                rCode = RCode.SERVER_UNAVAILABLE;
            } else {
                rCode = RCode.INTERNAL_SERVER_ERROR;
            }
        }

        /* 创建返回对象,优先使用 */
        R r = R.fault(rCode.getCode(), rCode.getMsg());
        r.setEx(throwable.getMessage());
        r.setFrom("[Gateway 网关] - [WrapperExceptionHandler:统一异常处理]");

        log.error("=====> 网关处理错误, 路径:[{}], 类名:[{}], 系统信息:[{}]",
                request.uri().getPath(),
                throwable.getClass().getCanonicalName(),
                null == throwable.getMessage() || "".equals(throwable.getMessage()) ? "无自定义消息" : throwable.getMessage());

        return JsonUtil.toMap(r);
    }

    @Override
    protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
        return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse);
    }


    /**
     * 根据 {@link WrapperExceptionHandler#getErrorAttributes(ServerRequest, ErrorAttributeOptions)} 的返回对象获取对应的 HttpStatus
     * @param errorAttributes 重写 [getErrorAttributes] 方法的返回对象, 会在此处获取http返回码
     */
    @Override
    protected int getHttpStatus(Map<String, Object> errorAttributes) {
//        int httCode = (int) (errorAttributes.get("status") == null ? errorAttributes.get("code") : errorAttributes.get("status"));
//        int statusCode = R.byCode(httCode).httpCode();
        return HttpStatus.OK.value();
    }
}
